#pragma once
#ifndef __POINTER__INCLUDED__HH__
#define __POINTER__INCLUDED__HH__

namespace Lit{
	template<typename T>
	class RefPtr{
		T* ptr;
	public:
		typedef T Type;
		typedef T* Ptr;

		RefPtr( ):ptr(0){}
		RefPtr( T * p ) : ptr(p){}
		RefPtr( const RefPtr<T> & rk ){ ptr=rk.ptr;}
		virtual ~RefPtr(){}
		
		RefPtr& operator=( const RefPtr<T>& rk ){ ptr = rk.ptr; return *this; }
		RefPtr& operator=( T* rk ){ ptr = rk; return *this; }

		Ptr operator*(){ if( !ptr )throw std::runtime_error("invalid ptr"); return ptr; }
		Ptr operator->(){ if( !ptr )throw std::runtime_error("invalid ptr"); return ptr; }

		const Ptr operator*() const { return get(); }
		const Ptr operator->() const { return get(); }

		Ptr get(){ if( !ptr )throw std::runtime_error("invalid ptr"); return ptr; }
		const Ptr get() const{ if( !ptr )throw std::runtime_error("invalid ptr"); return ptr; }

		RefPtr swap( const RefPtr<T>& rk ){
			RefPtr<T> old( *this );
			ptr = rk.ptr;
			return old;
		}
		operator bool() const{ return ptr!=NULL; }
		bool operator == ( const RefPtr<T>& rk ) const{ return ptr == rk.ptr; }
		bool operator != ( const RefPtr<T>& rk ) const{ return ptr != rk.ptr; }
		
		bool operator == ( T* rk ) const{ if(!rk) return false; return ptr == rk->ptr; }
		bool operator != ( T* rk ) const{ if(!rk) return false; return ptr != rk->ptr; }

		void destroy(){ if( ptr ) delete ptr, ptr=NULL; ptr=NULL; }
	};


	template<typename T>
	class MasterPtr
	{
	public:
		typedef T type;
		typedef T* type_ptr;
		typedef RefPtr<type> Ref;

	protected:
		T* mPtr;
		friend class MasterPtr<T>;
		void __set__null(){ mPtr = NULL; }
	public:
		MasterPtr( const MasterPtr<T>& rk ){ mPtr = rk.mPtr; const_cast<MasterPtr<T>*>( &rk )->mPtr = NULL; }
		MasterPtr( T*inst ){ mPtr = inst; }
		MasterPtr( ) : mPtr(0){}
		virtual ~MasterPtr(){ destroy(); }

		void destroy(){ if( mPtr ){ delete mPtr; mPtr = NULL; } }

		MasterPtr<T> swap( MasterPtr<T>& rk )
		{
			MasterPtr<T> ret(*this);
			mPtr = rk.mPtr;
			rk.__set__null();
			return ret;
		}
		MasterPtr<T>& operator=( MasterPtr<T>& rk ){ swap( rk ); return *this; }
		void assign( T* inst ){ destroy(); mPtr = inst; }

		Ref ref(){ return Ref(mPtr); }

		T* operator*(){ if( !mPtr )throw std::runtime_error("invalid ptr"); return mPtr; }
		T* operator->(){ if( !mPtr )throw std::runtime_error("invalid ptr"); return mPtr; }

		const T* operator*() const { return get(); }
		const T* operator->() const { return get(); }
		
		operator bool() const{ return mPtr!=NULL; }
		bool operator == ( const MasterPtr<T>& rk ) const{ return mPtr == rk.mPtr; }
		bool operator != ( const MasterPtr<T>& rk ) const{ return mPtr != rk.mPtr; }
		
		bool operator == ( T* rk ) const{ return mPtr == rk->mPtr; }
		bool operator != ( T* rk ) const{ return mPtr != rk->mPtr; }

		T* get(){ if( !mPtr )throw std::runtime_error("invalid ptr"); return mPtr; }
		const T* get() const{ if( !mPtr )throw std::runtime_error("invalid ptr"); return mPtr; }
	};
};

#endif